package com.apache.passport.jwt;

import com.apache.api.vo.ResultEntity;
import com.apache.jwt.Claims;
import com.apache.jwt.PostHttps;
import com.apache.passport.common.PassportHelper;
import com.apache.rpc.common.LoadRpcService;
import com.apache.rpc.entity.InterfaceRegister;
import com.apache.tools.StrUtil;
import com.apache.uct.common.LoginUser;
import com.apache.uct.common.PBOSSOTools;
import com.apache.uct.common.ToolsUtil;
import net.sf.json.JSONObject;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.apache.log4j.Logger;

import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

public abstract class CorsFilter implements Filter {

    protected Logger log = Logger.getLogger(getClass());

    protected JwtUtil jwt;

    //sso登录页面
    protected String login_url = "";

    //定自义登录页面
    protected String customLogin = "";

    //cookieName 名称
    protected String cookieName = "";

    //是否使用统一登录系统登录 T/F
    protected String login_pass = "";

    protected String reqUrl = "";

    protected String reqType = "";

    protected String checkIp = "";

    protected String checkPort = "";

    protected String isClearSession = "";

    protected String registryProtocol = "";

    //系统名称
    protected String sessionKey = "loginUser";

    //错误页面地址
    protected String errorPage = "";

    protected String defaultSso = "sso";

    protected String sysEname;


    public void init(FilterConfig filterConfig) {
        jwt = JwtUtil.newInstance();
        errorPage = StrUtil.doNull(filterConfig.getInitParameter("errorPage"), "/error.action");
        defaultSso = StrUtil.doNull(filterConfig.getInitParameter("defaultSso"), "sso")
                .toLowerCase();
        initValue();
    }

    protected void initValue() {
        //		XmlWhiteUtils.getInstance().deWhiteXml(whiteMap);//加载白名单
        customLogin = ToolsUtil.getInstance().getValueByKey("custom_login");
        //自定义登录页面
        login_url = ToolsUtil.getInstance().getValueByKey("uct_server");
        //cookieName 名称
        cookieName = ToolsUtil.getInstance().getValueByKey("cookieName");
        //是否使用统一登录系统登录 T/F
        login_pass = ToolsUtil.getInstance().getValueByKey("login.pass");
        reqUrl = ToolsUtil.getInstance().getValueByKey("req_url");
        //http,socket,https,webservice
        reqType = ToolsUtil.getInstance().getValueByKey("req_type");
        checkIp = ToolsUtil.getInstance().getValueByKey("check_url");
        checkPort = ToolsUtil.getInstance().getValueByKey("check_port");
        isClearSession = ToolsUtil.getInstance().getValueByKey("is_clear_session");
        registryProtocol = ToolsUtil.getInstance().getValueByKey("registry_protocol");
        sysEname = ToolsUtil.getInstance().getValueByKey("sysEname");
    }

    protected boolean jkWhite(String servletPath){
        List<String> whiteJK= PassportHelper.whiteJK;
        for (int i = 0; i < whiteJK.size(); i++) {
            String wurl = whiteJK.get(i);
            if (servletPath.startsWith(wurl)) {
                return true;
            }
        }
        return false;
    }

    public void destroy() {
    }

    protected String getLonginUrl(HttpServletRequest request, HttpServletResponse response,
            String tokenId) throws UnsupportedEncodingException {
        String loginUrl = "";
        if (StrUtil.isNotNull(tokenId) && tokenId.indexOf("uni_") > -1) {
            loginUrl = doSsoFiltersForEid(request, response, tokenId, "");
        } else if ("sso".equals(defaultSso)) {
            loginUrl = doSsoFilters(request, response, tokenId, "");
        } else if ("eid".equals(defaultSso)) {
            loginUrl = doSsoFiltersForEid(request, response, tokenId, "");
        } else {
            loginUrl = request.getContextPath() + StrUtil.doNull(customLogin, "/login.jsp");
        }
        return loginUrl;
    }

    /**
     * description: sso参数组装
     */
    protected String doSsoFilters(HttpServletRequest request, HttpServletResponse response,
            String tokenId, String pkt) throws UnsupportedEncodingException {
        String path = request.getServletPath();
        //要跳转到哪个url
        String gotoURL = request.getParameter("go");
        String csetUrl = request.getScheme() + "://" + request.getServerName() + ":" + request
                .getServerPort() + request.getContextPath();

        if (gotoURL == null) {
            gotoURL = request.getRequestURL().toString();
        }
        String reqParams = "";//customLogin
        if ("T".equals(ToolsUtil.getInstance().getValueByKey("is_url_params"))) {
            reqParams = PassportHelper.getInstance().getReqParams(request, "go");
            reqParams = PassportHelper.getInstance().isNov(reqParams, reqParams, "?" + reqParams);
        }

        ArrayList<String> lst = new ArrayList<String>();
        String sha1Rtn = "";
        if (StrUtil.isNull(tokenId) && StrUtil.isNotNull(pkt)) {//客户端调用
            StringBuffer tokenUrl = new StringBuffer();
            lst.add(login_url);
            lst.add(pkt);
            lst.add(gotoURL + reqParams);
            lst.add("apache");
            lst.add(csetUrl);
            Collections.sort(lst);
            sha1Rtn = PassportHelper.getInstance().SHA1(lst);
            log.info("login_url=" + login_url + "====pkt=" + pkt);
            if ("T".equals(login_pass)) {
                //如果cookie为空,则跳转到登录页面
                tokenUrl.append(login_url);
                tokenUrl.append("?");
                tokenUrl.append("tokenId=" + pkt);//设置远程cookie
                tokenUrl.append("&go=" + gotoURL + reqParams);
                tokenUrl.append("&ptlang=" + sha1Rtn);
                tokenUrl.append("&cset=" + csetUrl);
            } else {
                tokenUrl.append(login_url);
            }
            request.removeAttribute("tokenId");
            return tokenUrl.toString();
        }/////客户端调用结束

        //统一登录系统平台回调参数
        String cset = csetUrl + "/cset";
        lst.add(login_url);
        lst.add(sysEname);
        lst.add(cset);
        if (request.getRequestURI().equals(path + "/logout")) {
            lst.add(gotoURL);
        } else {
            lst.add(gotoURL + reqParams);
        }
        lst.add("apache");
        Collections.sort(lst);
        sha1Rtn = PassportHelper.getInstance().SHA1(lst);

        StringBuffer loginUrl = new StringBuffer();
        if ("T".equals(login_pass)) {
            //如果cookie为空,则跳转到登录页面
            loginUrl.append(login_url);
            loginUrl.append("?");
            loginUrl.append("_client=" + sha1Rtn);
            loginUrl.append("&");
            loginUrl.append("sys=" + sysEname);//系统名称
            loginUrl.append("&");
            loginUrl.append("cset=" + URLEncoder.encode(cset, "UTF-8"));//设置远程cookie
            loginUrl.append("&");
            loginUrl.append("go=" + URLEncoder.encode(gotoURL, "UTF-8") + reqParams);
        } else {
            loginUrl.append(login_url);
        }
        return loginUrl.toString();
    }

    /**
     * description: Eid参数组装
     */
    protected String doSsoFiltersForEid(HttpServletRequest request, HttpServletResponse response,
            String tokenId, String pkt) throws UnsupportedEncodingException {
        //要跳转到哪个url
        String gotoURL = request.getParameter("go");

        if (gotoURL == null) {
            gotoURL = request.getRequestURL().toString();
        }
        String reqParams = "";//customLogin
        if ("T".equals(ToolsUtil.getInstance().getValueByKey("is_url_params"))) {
            reqParams = PassportHelper.getInstance().getReqParams(request, "go,code");
            reqParams = PassportHelper.getInstance().isNov(reqParams, reqParams, "?" + reqParams);
        }

        ArrayList<String> lst = new ArrayList<String>();
        String sha1Rtn = "";
        if (StrUtil.isNull(tokenId) && StrUtil.isNotNull(pkt)) {//客户端调用
            StringBuffer tokenUrl = new StringBuffer();
            lst.add(login_url);
            lst.add("apache");
            Collections.sort(lst);
            sha1Rtn = PassportHelper.getInstance().SHA1(lst);
            log.info("login_url=" + login_url + "====pkt=" + pkt);
            if ("T".equals(login_pass)) {
                //如果cookie为空,则跳转到登录页面
                tokenUrl.append(login_url);
                tokenUrl.append("?_client=" + sha1Rtn);
                tokenUrl.append("&tokenId=" + pkt);//设置远程cookie
                tokenUrl.append("&clientid=" + sysEname);//系统名称
                tokenUrl.append("&response_type=" + "code");
                tokenUrl.append("&scope=" + "openid");
                tokenUrl.append("&go=" + gotoURL + reqParams);
            } else {
                tokenUrl.append(login_url);
            }
            request.removeAttribute("tokenId");
            return tokenUrl.toString();
        }/////客户端调用结束

        //统一登录系统平台回调参数
        lst.add(login_url);
        lst.add(sysEname);
        lst.add("apache");
        Collections.sort(lst);
        sha1Rtn = PassportHelper.getInstance().SHA1(lst);

        StringBuffer loginUrl = new StringBuffer();
        if ("T".equals(login_pass)) {
            //如果cookie为空,则跳转到登录页面
            loginUrl.append(login_url);
            loginUrl.append("?_client=" + sha1Rtn);
            loginUrl.append("&clientid=" + sysEname);//系统名称
            loginUrl.append("&response_type=" + "code");
            loginUrl.append("&scope=" + "openid");
            loginUrl.append("&go=" + URLEncoder.encode(gotoURL, "UTF-8") + reqParams);
        } else {
            loginUrl.append(login_url);
        }
        return loginUrl.toString();
    }

    /**
     * description:  获取accessToken
     */
    protected String getAccessToken(String code, HttpServletRequest req, HttpServletResponse resp) {
        String tokenId = "";
        try {
            if (StrUtil.isNull(login_url)) {
                login_url = ToolsUtil.getInstance().getValueByKey("uct_server");
            }
            String clientEname = ToolsUtil.getInstance().getValueByKey("sysEname");
            String url = login_url + "passport/outside/access_token";
            NameValuePair[] parasInput = new NameValuePair[3];
            parasInput[0] = new BasicNameValuePair("code", code);
            parasInput[1] = new BasicNameValuePair("clientid", clientEname);
            parasInput[2] = new BasicNameValuePair("grant_type", "authorization_code");
            String jsonStr = "";
            log.info("url=" + url);
            if (url.startsWith("https:")) {
                jsonStr = PostHttps.newInstance().getHttpsForStl(url, parasInput, "GET");
            } else {
                jsonStr = PostHttps.newInstance().getHttp(url, parasInput, "GET");
            }
            log.info("getAccessToken=" + jsonStr);
            if (StrUtil.isNull(jsonStr))
                return "";
            net.sf.json.JSONObject json = net.sf.json.JSONObject.fromObject(jsonStr);
            if ("200".equals(json.get("state"))) {
                String idToken = json.getString("id_token");
                Claims claims = JwtUtil.newInstance().uniParseJWT(idToken);
                if (null == claims) {
                    return "";
                }
                String aud = claims.getAudience();
                if (!aud.contains(clientEname))
                    return "";
                JSONObject ujson = JSONObject.fromObject(claims.get("u_info"));
                String userEname = ujson.getString("userEname");
                LoginUser loginUser = PBOSSOTools
                        .getLoginUserFromUserCenter(userEname, "uni_" + code);
                HttpSession session = req.getSession();
                session.setAttribute("loginUser", loginUser);
                session.setAttribute("id_token", idToken);
                session.setAttribute("access_token", claims.get("u_info"));
                session.setAttribute("token_code", code);
                Cookie ticket = new Cookie(cookieName, "uni_" + code);
                ticket.setPath("/");
                ticket.setMaxAge(-1);
                resp.addCookie(ticket);
                Cookie ucssoCKey = new Cookie("_uc.sso", userEname);
                ucssoCKey.setPath("/");
                ucssoCKey.setMaxAge(-1);
                resp.addCookie(ucssoCKey);
                tokenId = "uni_" + code;
            } else {
                log.info(json.get("msg"));
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return tokenId;
    }

    /**
     * description: 验证tokenId是否有效
     */
    protected boolean auditTokenAndSso(String tokenId, HttpServletRequest req,
            HttpServletResponse resp) {
        if (StrUtil.isNull(tokenId)) {
            return false;
        }
        String ss[] = tokenId.split("\\|");
        tokenId = ss[0];
        if (tokenId.indexOf("uni_") > -1) {
            String accessToken = String.valueOf(req.getSession().getAttribute("id_token"));
            if (StrUtil.isNull(accessToken)) {
                getAccessToken(tokenId.replace("uni_", ""), req, resp);
                accessToken = String.valueOf(req.getSession().getAttribute("id_token"));
            }
            if (StrUtil.isNull(accessToken)) {
                return false;
            }
            log.info("auditTokenAndSso=" + accessToken);
            Claims claims = JwtUtil.newInstance().uniParseJWT(accessToken);
            if (null == claims)
                return false;
            String aud = claims.getAudience();
            if (!aud.contains(sysEname))
                return false;
            long expiresOut = Long.valueOf(String.valueOf(claims.get(Claims.EXPIRATION)));
            long nowTime = System.currentTimeMillis() / 1000;
            if (nowTime > expiresOut) {
                return false;
            }
            return true;
        }

        long nowTimeLong = System.currentTimeMillis();
        Object obj = req.getSession().getAttribute("time_" + tokenId);
        if (null != obj) {//五分钟内不重复验证
            long upTimeLong = Long.valueOf(StrUtil.doNull(String.valueOf(obj), nowTimeLong + ""));
            if ((nowTimeLong - upTimeLong) < 5 * 60 * 1000) {
                return true;
            }
        }

        ResultEntity entity = this.checkToken(tokenId, req.getLocalAddr(), "checkToken", "");
        String str = String.valueOf(entity.getEntity());
        if (StrUtil.isNotNull(str) && tokenId.equalsIgnoreCase(str)) {
            Cookie ticket = new Cookie(cookieName, tokenId);
            ticket.setPath("/");
            ticket.setMaxAge(-1);
            Cookie ucssoCKey = new Cookie("_uc.sso", entity.getMessage());
            ucssoCKey.setPath("/");
            ucssoCKey.setMaxAge(-1);
            resp.addCookie(ticket);
            resp.addCookie(ucssoCKey);
            req.getSession().setAttribute("time_" + tokenId, nowTimeLong);
            return true;
        }
        return false;
    }

    /**
     * description:  验证token是否有效/退出系统
     * methodKey:checkToken/logout
     */
    protected ResultEntity checkToken(String tokenId, String ip, String methodKey,
            String userEname) {
        ResultEntity entity = null;
        if ("https".equalsIgnoreCase(ToolsUtil.getInstance().getValueByKey("req_type"))) {
            String httpsUrl = ToolsUtil.getInstance().getValueByKey("req_url");
            NameValuePair[] parasInput = new NameValuePair[4];
            parasInput[0] = new BasicNameValuePair("sysAccreditip", ip);
            parasInput[1] = new BasicNameValuePair("tokenId", tokenId);
            parasInput[2] = new BasicNameValuePair("sysEname", sysEname);
            parasInput[3] = new BasicNameValuePair("userEname", userEname);
            String jsonStr = PostHttps.newInstance().getHttpsForStl(httpsUrl, parasInput, "GET");
            entity = LoadRpcService.service().xmlToBean(jsonStr, ResultEntity.class);
        } else {
            Map<String, Object> param = new HashMap<String, Object>();
            param.put("sysAccreditip", ip);
            param.put("tokenId", tokenId);
            param.put("sysEname", sysEname);
            param.put("userEname", userEname);
            entity = LoadRpcService.service()
                    .doServiceClient("ssoService", methodKey, param, getInterfaceRegister());
        }
        return entity;
    }

    /**
     * description:  设置本地cookie
     *
     * @param req
     * @param resp
     */
    protected void setCookie(HttpServletRequest req, HttpServletResponse resp) {
        String token = req.getParameter("ticket");
        String ucsso = req.getParameter("ucsso");
        String gotoURL = req.getParameter("go");
        if (StrUtil.isNotNull(gotoURL)) {
            gotoURL = gotoURL.replaceAll("\\|", "&");
            try {
                if (gotoURL.indexOf("token_code") == -1 && StrUtil.isNotNull(token) && StrUtil
                        .isNotNull(ucsso)) {
                    Cookie ticket = new Cookie(cookieName, token);
                    ticket.setPath("/");
                    ticket.setMaxAge(-1);

                    Cookie ucssoCKey = new Cookie("_uc.sso", ucsso);
                    ucssoCKey.setPath("/");
                    ucssoCKey.setMaxAge(-1);
                    resp.addCookie(ticket);
                    resp.addCookie(ucssoCKey);
                    if (gotoURL.indexOf("?tokenId=") != -1) {
                        gotoURL = gotoURL.replaceAll("tokenId=" + token + "&", "");
                    } else {
                        gotoURL = gotoURL.replaceAll("&tokenId=" + token, "");
                    }
                }
                resp.sendRedirect(gotoURL);
                return;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private InterfaceRegister getInterfaceRegister() {
        InterfaceRegister register = new InterfaceRegister();
        String type = ToolsUtil.getInstance().getValueByKey("req_type");
        String ip = ToolsUtil.getInstance().getValueByKey("check_url");
        if ("https".equalsIgnoreCase(type)) {
            String ssoPath = ToolsUtil.getInstance().getValueByKey("req_url");
            register.setAddress(ssoPath);
            register.setCallType("https");
        } else if ("socket".equals(type) || StrUtil.isNotNull(ip)) {
            String port = ToolsUtil.getInstance().getValueByKey("check_port");
            register.setAddress(ip);
            register.setPort(port);
            register.setCallType("socket");
        } else {
            String ssoPath = ToolsUtil.getInstance().getValueByKey("req_url");
            register.setAddress(ssoPath);
            register.setCallType("http");
        }
        return register;
    }

}